package com.example.security.service.impl;

import com.example.security.entity.SysPermission;
import com.example.security.exception.BusinessException;
import com.example.security.mapper.PermissionMapper;
import com.example.security.mapper.RolePermissionMapper;
import com.example.security.mapper.UserRoleMapper;
import com.example.security.mapper.UserMapper;
import com.example.security.service.PermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class PermissionServiceImpl implements PermissionService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final PermissionMapper permissionMapper;
    private final RolePermissionMapper rolePermissionMapper;
    private final UserRoleMapper userRoleMapper;
    private final UserMapper userMapper;

    @Override
    @Cacheable(value = "permissions", key = "#userId")
    public Set<String> getUserPermissions(Long userId) {
        return permissionMapper.selectPermissionsByUserId(userId);
    }

    @Override
    public List<SysPermission> getMenuTree() {
        List<SysPermission> allPermissions = permissionMapper.selectAll();
        return buildTree(allPermissions, null);
    }

    @Override
    @CacheEvict(value = "permissions", allEntries = true)
    public void refreshPermissionCache() {
        log.info("刷新权限缓存");
    }

    @Override
    @CacheEvict(value = {"permissions", "rolePermissions"}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void updateRolePermissions(Long roleId, List<Long> permissionIds) {
        // 更新角色权限
        rolePermissionMapper.deleteByRoleId(roleId);
        if (!CollectionUtils.isEmpty(permissionIds)) {
            rolePermissionMapper.batchInsert(roleId, permissionIds);
        }
        
        // 获取该角色下的所有用户
        List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(roleId);
        
        // 清除这些用户的权限缓存
        userIds.forEach(userId -> {
            String username = userMapper.selectUsernameById(userId);
            redisTemplate.delete("permissions:" + username);
        });
    }

    @Override
    public List<SysPermission> getPermissionTree() {
        List<SysPermission> allPermissions = permissionMapper.selectAll();
        return buildTree(allPermissions, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPermission(SysPermission permission) {
        // 检查权限标识是否存在
        if (permissionMapper.selectByEnname(permission.getEnname()) != null) {
            throw new BusinessException("权限标识已存在");
        }
        
        permissionMapper.insert(permission);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePermission(SysPermission permission) {
        // 检查权限是否存在
        if (permissionMapper.selectById(permission.getId()) == null) {
            throw new BusinessException("权限不存在");
        }
        
        // 检查权限标识是否重复
        SysPermission existPermission = permissionMapper.selectByEnname(permission.getEnname());
        if (existPermission != null && !existPermission.getId().equals(permission.getId())) {
            throw new BusinessException("权限标识已存在");
        }
        
        permissionMapper.update(permission);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePermission(Long id) {
        // 检查是否有子权限
        if (permissionMapper.countByParentId(id) > 0) {
            throw new BusinessException("存在子权限，不能删除");
        }
        
        permissionMapper.deleteById(id);
    }

    private List<SysPermission> buildTree(List<SysPermission> permissions, Long parentId) {
        return permissions.stream()
            .filter(p -> Objects.equals(p.getParentId(), parentId))
            .peek(p -> {
                List<SysPermission> children = buildTree(permissions, p.getId());
                p.setChildren(children);
            })
            .collect(Collectors.toList());
    }
} 